package cn.gan.loveofsoul.commons.utils;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.security.Key;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * MD5加密、 3-DES加密、 base64编码、 URLEncoder编码 ( 默认编码为UTF-8 )
 *
 * @Description:
 * @Author: Jayh
 * @CreateTime: 2017年7月17日 上午10:27:50
 */
public class Encrypt {
    
    private static Encrypt encrypt;
    
    public static String MD5(String string) {
        
        byte[] hash;
        try {
            hash = MessageDigest.getInstance("MD5").digest(string.getBytes(Constants.DEFAULT_ENCODING));
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("Huh, MD5 should be supported", e);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException("Huh, UTF-8 should be supported", e);
        }
        
        StringBuilder hex = new StringBuilder(hash.length * 2);
        for (byte b : hash) {
            if ((b & 0xFF) < 0x10) {
                hex.append("0");
            }
            hex.append(Integer.toHexString(b & 0xFF));
        }
        return hex.toString();
    }
    
    /**
     * 进行MD5加密
     *
     * @param str
     * @return
     */
    public byte[] md5(String str) {
        
        byte[] returnByte = null;
        try {
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            returnByte = md5.digest(str.getBytes(Constants.DEFAULT_ENCODING));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return returnByte;
    }
    
    /**
     * 进行MD5加密
     *
     * @param str
     * @param charset
     * @return
     */
    public byte[] md5(String str, String charset) {
        
        byte[] returnByte = null;
        try {
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            returnByte = md5.digest(str.getBytes(charset));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return returnByte;
    }
    
    /**
     * 得到3-DES的密钥匙 密钥匙为24个字节，md5加密出来的是16个字节，因此后面补8个字节的0
     *
     * @param spKey
     * @return
     */
    private byte[] getEnKey(String spKey) {
        
        byte[] desKey = null;
        try {
            byte[] desKey1 = md5(spKey);
            desKey = new byte[24];
            int i = 0;
            while (i < desKey1.length && i < 24) {
                desKey[i] = desKey1[i];
                i++;
            }
            if (i < 24) {
                desKey[i] = 0;
                i++;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return desKey;
    }
    
    /**
     * 3-DES加密
     *
     * @param src
     * @param enKey
     * @return
     */
    public byte[] Encrypt(byte[] src, byte[] enKey) {
        
        byte[] encryptedData = null;
        try {
            Key sKey = new SecretKeySpec(enKey, "DES");
            Cipher cp = Cipher.getInstance("DES/CBC/Nopadding");
            byte biv[] = new byte[8];
            IvParameterSpec iv = new IvParameterSpec(biv);
            cp.init(1, sKey, iv);
            int len = src.length % 8 != 0 ? (src.length / 8 + 1) * 8 : src.length;
            byte[] resMisdn = new byte[len];
            System.arraycopy(src, 0, resMisdn, 0, src.length);
            encryptedData = cp.doFinal(resMisdn);
            
        } catch (Exception e) {
            e.printStackTrace();
        }
        return encryptedData;
    }
    
    /**
     * 对字符串进行Base64编码
     *
     * @param byte[] src 要进行编码的字符
     * @return String 进行编码后的字符串
     */
    public String getBase64Encode(byte[] src) {
        
        String requestValue = "";
        try {
            BASE64Encoder base64en = new BASE64Encoder();
            requestValue = base64en.encode(src);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return requestValue;
    }
    
    /**
     * 去掉字符串的换行符号 ( base64编码3-DES的数据时，得到的字符串有换行符号 )
     *
     * @param str
     * @return
     */
    private String filter(String str) {
        
        String output = null;
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < str.length(); i++) {
            int asc = str.charAt(i);
            if (asc != 10 && asc != 13) {
                sb.append(str.subSequence(i, i + 1));
            }
        }
        output = new String(sb);
        return output;
    }
    
    /**
     * 3-DES加密
     *
     * @param src
     * @param spkey
     * @return
     */
    public String get3DESEncrypt(String src, String spkey) {
        
        String requestValue = "";
        try {
            // 得到3-DES的密钥匙
            byte[] enKey = new byte[8]; // 密钥文件(byte)
            System.arraycopy(spkey.getBytes(), 0, enKey, 0, spkey.getBytes().length);
            // 要进行3-DES加密的内容在进行\"UTF-8\"取字节
            byte[] src2 = src.getBytes(Constants.DEFAULT_ENCODING);
            // 进行3-DES加密后的内容的字节
            byte[] encryptedData = Encrypt(src2, enKey);
            // 进行3-DES加密后的内容进行BASE64编码
            String base64String = getBase64Encode(encryptedData);
            // BASE64编码去除换行符后
            String base64Encrypt = filter(base64String);
            requestValue = base64Encrypt;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return requestValue;
    }
    
    /**
     * 对字符串进行URLDecoder.decode(strEncoding)解码
     *
     * @param src
     * @return
     */
    public String getURLDecoderdecode(String src) {
        
        String requestValue = "";
        try {
            requestValue = URLDecoder.decode(src, Constants.DEFAULT_ENCODING);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return requestValue;
    }
    
    /**
     * 进行3-DES解密
     *
     * @param debase64
     * @param spKey
     * @return
     */
    public String deCrypt(byte[] debase64, String spKey) {
        
        String strDe = null;
        try {
            byte[] enKey = new byte[8]; // 密钥文件(byte)
            System.arraycopy(spKey.getBytes(), 0, enKey, 0, spKey.getBytes().length);
            Key sKey1 = new SecretKeySpec(enKey, "DES");
            Cipher cp = Cipher.getInstance("DES/CBC/Nopadding");
            byte biv[] = new byte[8];
            IvParameterSpec iv = new IvParameterSpec(biv);
            cp.init(Cipher.DECRYPT_MODE, sKey1, iv);
            byte ciphertext1[] = cp.doFinal(debase64);
            strDe = new String(ciphertext1, Constants.DEFAULT_ENCODING).trim();
        } catch (Exception ex) {
            strDe = "";
            ex.printStackTrace();
        }
        return strDe;
    }
    
    /**
     * 进行3-DES解密
     *
     * @param src
     * @param spkey
     * @return
     */
    public String get3DESDecrypt(String src, String spkey) {
        
        String requestValue = "";
        try {
            BASE64Decoder base64Decode = new BASE64Decoder();
            byte[] base64DValue = base64Decode.decodeBuffer(src);
            // 要进行3-DES加密的内容在进行\"UTF-16LE\"取字节
            requestValue = deCrypt(base64DValue, spkey);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return requestValue;
    }
    
    public static Encrypt getEncrypt() {
        
        if (encrypt == null) {
            encrypt = new Encrypt();
        }
        return encrypt;
    }
    
    public static void main(String[] args) {
        
        System.out.println(Encrypt.MD5("7778511a."));
    }
    
}
